﻿using System;
using System.Collections.Concurrent;
using System.ComponentModel.Composition;
using OperationPlugins.Compositions;

namespace OperationPlugins.Proxies
{
    public static class Proxy
    {
        /// <summary>
        /// The proxy generator.
        /// </summary>
        private static IProxyGenerator Generator { set; get; }

        /// <summary>
        /// The proxy activator.
        /// </summary>
        private static IProxyActivator Activator { set; get; }

        /// <summary>
        /// The type validator.
        /// </summary>
        private static ITypeValidator Validator { set; get; }

        /// <summary>
        /// The cache for proxy types.
        /// </summary>
        private static readonly ConcurrentDictionary<Type, Type> ProxyCache = new ConcurrentDictionary<Type, Type>();

        public static T GetFor<T>()
        {
            OperationPluginsEnvironment.CheckStatus();

            Type type = typeof(T);

            Type proxyType;

            if (ProxyCache.TryGetValue(type, out proxyType) == false)
            {
                string message;
                if (Validator.IsValid(type, out message) == false)
                {
                    throw new ArgumentException(message);
                }

                proxyType = Generator.Generate(type);

                ProxyCache.TryAdd(type, proxyType);
            }

            T proxy = Activator.Activate<T>(proxyType);

            return proxy;
        }

        /// <summary>
        /// Initialize. 
        /// </summary>
        [Export(typeof(IInitializable))]
        private sealed class Initializer : IInitializable
        {
            void IInitializable.Initialize(InitializationContext context)
            {
                Generator = context.CompositionContainer.GetPlugin<IProxyGenerator>();
                Activator = context.CompositionContainer.GetPlugin<IProxyActivator>();
                Validator = context.CompositionContainer.GetPlugin<ITypeValidator>();
            }
        }

    }
}
